﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using Ninject;
using XHouse.Data.Interfaces;
using XHouse.Model;

namespace XHouseWeb.Helpers
{
    public class ImageProvider
    {
        // TODO: Esto podría leerse desde el web.config en el constructor estático
        private const string BasePath = "~/Images/";
        private readonly string[] _extensionesPermitidas = { ".png", ".jpg", ".gif", ".jpeg", ".jpe", ".tif", ".tiff" };
        private readonly string[] _contentTypes = { "image/jpeg", "image/tiff", "image/png"};

        // Imagenes por defecto
        private const string DefaultTipoAparatoImage = "default-ta.png";
        private const string DefaultEscenaImage = "default-esc.jpg";

        private readonly IRepository<Imagen> _imageRepository;

        [Inject]
        public ImageProvider(IRepository<Imagen> repository)
        {
            if (repository == null)
                throw new ArgumentNullException("repository");

            _imageRepository = repository;
        }

        public string GetImagePath(ImagenTipoObjeto tipoObjeto, int idObjeto)
        {
            var result = _imageRepository.Get(img => img.TipoObjeto == tipoObjeto && img.IdObjeto == idObjeto);

            var resultArray = result as Imagen[] ?? result.ToArray();

            return resultArray.Any()
                       ? GetImagePath(tipoObjeto, resultArray.First().Path)
                       : GetDefaultImagePath(tipoObjeto);
        }

        public string GetImagePath(ImagenTipoObjeto tipoObjeto, string nombreArchivo)
        {
            string fullPath = BasePath + nombreArchivo;

            // TODO: Acá se podría loguear o de alguna manera dejar un registro cuando la imagen no existe
            return File.Exists(HttpContext.Current.Server.MapPath(fullPath)) ? fullPath : GetDefaultImagePath(tipoObjeto);
        }

        public string GetImagePath(Imagen img)
        {
            return GetImagePath(img.TipoObjeto, img.Path);
        }

        /// <summary>
        /// Indica si el objeto tiene o no seteada una imagen.
        /// </summary>
        /// <param name="tipoObjeto">Tipo de objeto</param>
        /// <param name="idObjeto">Id del objeto</param>
        /// <returns>Retorna 'true' si hay una imagen cargada para el objeto.</returns>
        public bool HaveImage(ImagenTipoObjeto tipoObjeto, int idObjeto)
        {
            var result = _imageRepository.Get(img => img.TipoObjeto == tipoObjeto && img.IdObjeto == idObjeto);
            var resultArray = result as Imagen[] ?? result.ToArray();
            return resultArray.Any();
        }

        public string GetDefaultImagePath(ImagenTipoObjeto tipoObjeto)
        {
            string path = "";

            switch (tipoObjeto)
            {
                case ImagenTipoObjeto.TipoAparato:
                    path = DefaultTipoAparatoImage;
                    break;
                case ImagenTipoObjeto.Ambiente:
                    path = DefaultEscenaImage;
                    break;
            }

            return BasePath + path;
        }

        public void Save(HttpPostedFileBase file, int idObjeto, ImagenTipoObjeto tipoObjeto)
        {
            if (file == null || file.ContentLength <= 0 || string.IsNullOrEmpty(file.FileName))
                return;
            
            var fileName = Path.GetFileName(file.FileName).ToLower();
            var img = new Imagen(tipoObjeto, idObjeto, fileName);

            try
            {
                var path = Path.Combine(HttpContext.Current.Server.MapPath(BasePath), img.Path);
                file.SaveAs(path);
            }
            catch (Exception e)
            {
                throw new Exception("Error al guardar la imagen: " + img.Path, e);
            }

            _imageRepository.Add(img);
            _imageRepository.Save();
        }

        public void Remove(int idObjeto, ImagenTipoObjeto tipoObjeto)
        {
            var result = _imageRepository.Get(img => img.TipoObjeto == tipoObjeto && img.IdObjeto == idObjeto);

            if (!result.Any())
                return;

            _imageRepository.Remove(result.First().Id);
            _imageRepository.Save();
        }

        /// <summary>
        /// Valida el archivo pasados como parámetro.
        /// </summary>
        /// <param name="file"></param>
        /// <param name="errorMessage"></param>
        /// <returns></returns>
        public bool ValidateFile(HttpPostedFileBase file, out string[] errorMessage)
        {
            var listaErrores = new List<string>();

            if (file.ContentLength <= 0)
                listaErrores.Add("El archivo adjuntado está vacío.");

            // TODO: Chequear tamaño máximo.

            if (string.IsNullOrEmpty(file.ContentType) || !_contentTypes.Contains(file.ContentType))
                listaErrores.Add("El archivo adjuntado no es una imagen.");

            var ext = Path.GetExtension(file.FileName).ToLower();
            
            if (!string.IsNullOrEmpty(ext) && !_extensionesPermitidas.Contains(ext))
            {
                var extPermString = new StringBuilder();

                for (var i = 0; i < _extensionesPermitidas.Length; i++)
                {
                    extPermString.Append(_extensionesPermitidas[i]);

                    if (i < _extensionesPermitidas.Length - 1)
                        extPermString.Append(", ");
                }
                listaErrores.Add(string.Format("Solo se aceptan archivos con las siguientes extensiones: <strong>{0}</strong>.", extPermString));
            }

            errorMessage = listaErrores.ToArray();
            return errorMessage.Length < 1;
        }
    }
}